package com.sujeet.learning.caching;

public class LinkedList<T> {

	private Element<T> start = null;
	private int size = 0;
	private Element<T> end = null;

	public LinkedList() {
		start = new Element<T>(null, null);
		end = new Element<T>(null, null);
	}

	/**
	 * add at the end
	 * 
	 * @param item
	 * @return
	 */
	public boolean add(T item) {
		Element<T> curr = start;
		boolean res = false;
		if (curr.next() == null) {
			// first element getting added;
			curr.value(null);
			curr.next(new Element<T>(item, end));
			res = true;
			++size;
		} else {
			while (curr.next() != end) {
				curr = curr.next();
			}
			// new element with next as null
			Element<T> toAdd = new Element<T>(item, end);
			curr.next(toAdd);
			res = true;
			++size;
		}
		return res;
	}

	public boolean remove(T item) {
		boolean res = false;
		if (size == 0) return res;
		Element<T> prev = start;
		Element<T> curr = start.next();
		if (curr.value().equals(item)) {
			// first element being removed
			start.next(curr.next());
			--size;
			res = true;
			return res;
		}
		while (curr != end) {
			if (curr.value().equals(item)) {
				prev.next(curr.next());
				--size;
				res = true;
				break;
			}
			prev = curr;
			curr = curr.next();
		}
		if (curr == end) {
			if (curr.value().equals(item)) {
				prev.next(end);
				--size;
				res = true;
			}
		}
		return res;
	}

	public String toString() {
		if (size == 0)
			return "";
		StringBuffer sb = new StringBuffer();
		Element<T> curr = start;
		while (curr.next() != end) {
			if (curr.value() != null) {
				sb = sb.append(curr.value().toString());
				sb = sb.append(" ");
			}
			curr = curr.next();
		}
		sb = sb.append(curr.value().toString());
		return sb.toString();
	}

	public int size() {
		return size;
	}

}

class Element<T> {
	private T value = null;
	private Element<T> next = null;

	public Element(T value, Element<T> next) {
		// creating the start element
		this.value = value;
		this.next = next;
	}

	public T value() {
		return value;
	}

	public Element<T> next() {
		return next;
	}

	public void value(T value) {
		this.value = value;
	}

	public void next(Element<T> next) {
		this.next = next;
	}

	public boolean equals(Object that) {
		if (that == null)
			return false;
		if (that instanceof Element) {
			@SuppressWarnings("unchecked")
			Element<T> thatObj = (Element<T>) that;
			if (thatObj.value().equals(this.value())
					&& thatObj.next().equals(this.next())) {
				return true;
			}
		}
		return false;
	}
}
